package com.smart.community.commons.utils;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 配置加密工具类
 * @author Wu.Liang
 * @since 2024-12-19
 * @version 1.0.0
 */
@Slf4j
public class ConfigEncryptionUtil {
    
    /**
     * 加密算法
     */
    private static final String ALGORITHM = "AES";
    
    /**
     * 密钥长度
     */
    private static final int KEY_SIZE = 256;
    
    /**
     * 默认密钥
     */
    private static final String DEFAULT_KEY = "SmartCommunity2024!@#";
    
    /**
     * 生成AES密钥
     * 
     * @return Base64编码的密钥
     */
    public static String generateKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
            keyGenerator.init(KEY_SIZE);
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            log.error("生成AES密钥失败", e);
            return null;
        }
    }
    
    /**
     * 加密字符串
     * 
     * @param plaintext 明文
     * @return 加密后的字符串
     */
    public static String encrypt(String plaintext) {
        return encrypt(plaintext, DEFAULT_KEY);
    }
    
    /**
     * 加密字符串
     * 
     * @param plaintext 明文
     * @param key 密钥
     * @return 加密后的字符串
     */
    public static String encrypt(String plaintext, String key) {
        if (StringUtils.isEmpty(plaintext)) {
            return plaintext;
        }
        
        try {
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            
            byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            log.error("加密失败: plaintext={}", plaintext, e);
            return null;
        }
    }
    
    /**
     * 解密字符串
     * 
     * @param ciphertext 密文
     * @return 解密后的字符串
     */
    public static String decrypt(String ciphertext) {
        return decrypt(ciphertext, DEFAULT_KEY);
    }
    
    /**
     * 解密字符串
     * 
     * @param ciphertext 密文
     * @param key 密钥
     * @return 解密后的字符串
     */
    public static String decrypt(String ciphertext, String key) {
        if (StringUtils.isEmpty(ciphertext)) {
            return ciphertext;
        }
        
        try {
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            
            byte[] encryptedBytes = Base64.getDecoder().decode(ciphertext);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("解密失败: ciphertext={}", ciphertext, e);
            return null;
        }
    }
    
    /**
     * 获取密钥规范
     * 
     * @param key 密钥
     * @return 密钥规范
     */
    private static SecretKeySpec getSecretKeySpec(String key) {
        try {
            // 使用SHA-256生成固定长度的密钥
            java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(key.getBytes(StandardCharsets.UTF_8));
            return new SecretKeySpec(hash, ALGORITHM);
        } catch (Exception e) {
            log.error("生成密钥规范失败: key={}", key, e);
            throw new RuntimeException("生成密钥规范失败", e);
        }
    }
    
    /**
     * 检查字符串是否为加密的
     * 
     * @param text 文本
     * @return 是否为加密的
     */
    public static boolean isEncrypted(String text) {
        if (StringUtils.isEmpty(text)) {
            return false;
        }
        
        try {
            // 尝试Base64解码
            Base64.getDecoder().decode(text);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
    
    /**
     * 加密配置值
     * 
     * @param configKey 配置键
     * @param configValue 配置值
     * @return 加密后的配置值
     */
    public static String encryptConfigValue(String configKey, String configValue) {
        if (StringUtils.isEmpty(configValue)) {
            return configValue;
        }
        
        // 检查是否需要加密
        if (shouldEncrypt(configKey)) {
            return encrypt(configValue);
        }
        
        return configValue;
    }
    
    /**
     * 解密配置值
     * 
     * @param configKey 配置键
     * @param configValue 配置值
     * @return 解密后的配置值
     */
    public static String decryptConfigValue(String configKey, String configValue) {
        if (StringUtils.isEmpty(configValue)) {
            return configValue;
        }
        
        // 检查是否需要解密
        if (shouldDecrypt(configKey)) {
            return decrypt(configValue);
        }
        
        return configValue;
    }
    
    /**
     * 检查是否需要加密
     * 
     * @param configKey 配置键
     * @return 是否需要加密
     */
    private static boolean shouldEncrypt(String configKey) {
        if (StringUtils.isEmpty(configKey)) {
            return false;
        }
        
        String lowerKey = configKey.toLowerCase();
        return lowerKey.contains("password") || 
               lowerKey.contains("secret") || 
               lowerKey.contains("key") || 
               lowerKey.contains("token") ||
               lowerKey.contains("auth");
    }
    
    /**
     * 检查是否需要解密
     * 
     * @param configKey 配置键
     * @return 是否需要解密
     */
    private static boolean shouldDecrypt(String configKey) {
        if (StringUtils.isEmpty(configKey)) {
            return false;
        }
        
        String lowerKey = configKey.toLowerCase();
        return lowerKey.contains("password") || 
               lowerKey.contains("secret") || 
               lowerKey.contains("key") || 
               lowerKey.contains("token") ||
               lowerKey.contains("auth");
    }
    
    /**
     * 生成随机密钥
     * 
     * @param length 密钥长度
     * @return 随机密钥
     */
    public static String generateRandomKey(int length) {
        if (length <= 0) {
            length = 32;
        }
        
        try {
            SecureRandom random = new SecureRandom();
            byte[] bytes = new byte[length];
            random.nextBytes(bytes);
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            log.error("生成随机密钥失败: length={}", length, e);
            return null;
        }
    }
    
    /**
     * 生成随机密钥（默认长度32）
     * 
     * @return 随机密钥
     */
    public static String generateRandomKey() {
        return generateRandomKey(32);
    }
}
